package com.wonderful.mall.product.service.impl;

import com.wonderful.mall.product.service.CategoryBrandRelationService;
import com.wonderful.mall.product.vo.Catalog2Vo;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wonderful.common.utils.PageUtils;
import com.wonderful.common.utils.Query;

import com.wonderful.mall.product.dao.CategoryDao;
import com.wonderful.mall.product.entity.CategoryEntity;
import com.wonderful.mall.product.service.CategoryService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;


@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {
    @Resource
    private CategoryBrandRelationService categoryBrandRelationService;
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<>()
        );

        return new PageUtils(page);
    }

    /**
     * 查出所有分类,组装成父子树形结构
     */
    @Override
    public List<CategoryEntity> listWithTree() {
//        // 从pms_category中查询出所有分类
        List<CategoryEntity> entities = baseMapper.selectList(null);
        // list对象转换为流
        Stream<CategoryEntity> entityStream = entities.stream();
        // 过滤出所有父类id为0的目录，即根目录
        Stream<CategoryEntity> entityStreamLevel1 = entityStream.filter(categoryEntity -> categoryEntity.getParentCid() == 0);
        //给每一个父目录设置子目录
        Stream<CategoryEntity> childrenSettledMenu = entityStreamLevel1.peek(menu -> menu.setChildren(getChildren(menu, entities)));
        //排序
        Stream<CategoryEntity> sortedMenu = childrenSettledMenu.sorted(Comparator.comparingInt(menu -> (menu.getSort() == null ? 0 : menu.getSort())));
        //收集为list并返回
        return sortedMenu.collect(Collectors.toList());
    }

    @Override
    public void removeMenuByIds(List<Long> asList) {
        //TODO 检查当前菜单是否被引用
        baseMapper.deleteBatchIds(asList);
        //逻辑删除

    }

    //categoryServiceImpl实现方法
    //查找完整路径方法
    @Override
    public Long[] findCatelogPath(Long catelogId) {
        List<Long> paths = new ArrayList<>();
        List<Long> parentPath = findParentPath(catelogId, paths);
        Collections.reverse(parentPath);
        int size = parentPath.size();
        return parentPath.toArray(new Long[size]);
    }

    @Override
    @Transactional
//    @CacheEvict(value = {"category"},key = "'getLevel1Category'")
//    @CacheEvict(value = {"category"},allEntries = true)
    @Caching(evict = {
            @CacheEvict(value = {"category"}, key = "'getLevel1Category'"),
            @CacheEvict(value = {"category"}, key = "'getCatalogJson'")
    })
    public void updateCascade(CategoryEntity category) {
        this.updateById(category);
        categoryBrandRelationService.updateCategory(category.getCatId(), category.getName());
    }

    @Cacheable(value = {"category"}, key = "#root.method.name")//需要缓存的数据需要指定缓存分区(按业务类型分区)
    @Override
    public List<CategoryEntity> getLevel1Category() {
        return baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("cat_level", 1));
    }

    @Override
    @Cacheable(value = {"category"}, key = "#root.method.name")
    public Map<String, List<Catalog2Vo>> getCatalogJson() {
        //优化业务逻辑，仅查询一次数据库
        List<CategoryEntity> categoryEntities = this.list();
        //查出所有一级分类
        List<CategoryEntity> level1Categories = getCategoryByParentCid(categoryEntities, 0L);
        return level1Categories.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
            //遍历查找出二级分类
            List<CategoryEntity> level2Categories = getCategoryByParentCid(categoryEntities, v.getCatId());
            //封装二级分类到vo并且查出其中的三级分类
            return level2Categories.stream().map(cat -> {
                //遍历查出三级分类并封装
                List<CategoryEntity> level3category = getCategoryByParentCid(categoryEntities, cat.getCatId());
                List<Catalog2Vo.Catalog3Vo> catalog3Vos = null;
                if (level3category != null) {
                    catalog3Vos = level3category.stream()
                            .map(level3 -> new Catalog2Vo.Catalog3Vo(level3.getParentCid().toString(), level3.getCatId().toString(), level3.getName()))
                            .collect(Collectors.toList());
                }
                return new Catalog2Vo(v.getCatId().toString(), catalog3Vos, cat.getCatId().toString(), cat.getName());
            }).collect(Collectors.toList());
        }));
    }

///    public Map<String, List<Catalog2Vo>> getCatalogJsonFromDb() {
//        synchronized (this) {
//            //查询数据库之前先查询缓存
//            String catalogJSON = stringRedisTemplate.opsForValue().get("catalogJSON");
//            if (StringUtils.hasText(catalogJSON)) {
//                //缓存不为空 返回
//                return JSON.parseObject(catalogJSON, new TypeReference<Map<String, List<Catalog2Vo>>>() {
//                });
//            }
//            System.out.println("正在查询数据库");
//            //优化业务逻辑，仅查询一次数据库
//            List<CategoryEntity> categoryEntities = this.list();
//            //查出所有一级分类
//            List<CategoryEntity> level1Categories = getCategoryByParentCid(categoryEntities, 0L);
//            Map<String, List<Catalog2Vo>> collect = level1Categories.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
//                //遍历查找出二级分类
//                List<CategoryEntity> level2Categories = getCategoryByParentCid(categoryEntities, v.getCatId());
//                //封装二级分类到vo并且查出其中的三级分类
//                return level2Categories.stream().map(cat -> {
//                    //遍历查出三级分类并封装
//                    List<CategoryEntity> level3category = getCategoryByParentCid(categoryEntities, cat.getCatId());
//                    List<Catalog2Vo.Catalog3Vo> catalog3Vos = null;
//                    if (level3category != null) {
//                        catalog3Vos = level3category.stream()
//                                .map(level3 -> new Catalog2Vo.Catalog3Vo(level3.getParentCid().toString(), level3.getCatId().toString(), level3.getName()))
//                                .collect(Collectors.toList());
//                    }
//                    return new Catalog2Vo(v.getCatId().toString(), catalog3Vos, cat.getCatId().toString(), cat.getName());
//                }).collect(Collectors.toList());
//            }));
//            stringRedisTemplate.opsForValue().set("catalogJSON", JSON.toJSONString(collect), 1, TimeUnit.DAYS);
//            return collect;
//        }
//    }
///
///    public Map<String, List<Catalog2Vo>> getCatalogJsonFromDbWithDistributedLock() {
//        String uuid = UUID.randomUUID().toString();
//        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent("lock", uuid, 300, TimeUnit.SECONDS);
//        if (Boolean.TRUE.equals(lock)) {
//            //加锁成功
//            System.out.println("获取锁成功*******");
//            Map<String, List<Catalog2Vo>> jsonFromDb;
//            try {
//                jsonFromDb = getCatalogJsonFromDb();
//            } catch (Exception e) {
//                throw new RuntimeException(e);
//            } finally {
//                //删除锁
//                String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
//                stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList("lock", uuid));
//            }
//            return jsonFromDb;
//        } else {
//            //加锁失败
//            System.out.println("获取锁失败，等待重试--------");
//            try {
//                Thread.sleep(300);
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//            return getCatalogJsonFromDbWithDistributedLock();
//        }
//    }
///
///    public Map<String, List<Catalog2Vo>> getCatalogJsonFromDbWithRedissonLock() {
//        RLock lock = redissonClient.getLock("catalogJson-lock");
//        lock.lock();
//        Map<String, List<Catalog2Vo>> jsonFromDb;
//        try {
//            jsonFromDb = getCatalogJsonFromDb();
//        } catch (Exception e) {
//            throw new RuntimeException(e);
//        } finally {
//            lock.unlock();
//        }
//        return jsonFromDb;
//    }


    private List<CategoryEntity> getCategoryByParentCid(List<CategoryEntity> categoryEntities, long l) {
        return categoryEntities.stream().filter(item -> item.getParentCid() == l).collect(Collectors.toList());
    }

    //递归查找父节点id
    public List<Long> findParentPath(Long catelogId, List<Long> paths) {
        //1、收集当前节点id
        paths.add(catelogId);
        CategoryEntity byId = this.getById(catelogId);
        if (byId.getParentCid() != 0) {
            findParentPath(byId.getParentCid(), paths);
        }
        return paths;
    }

    /**
     * 获取当前目录的子目录；
     * root为当前目录，all为所有目录
     */
    private List<CategoryEntity> getChildren(CategoryEntity root, List<CategoryEntity> all) {

        Stream<CategoryEntity> allCategory = all.stream();
        //对每一条目录过滤，如果这条目录的父id等于root目录的id，就返回成为新的stream对象
        Stream<CategoryEntity> children = allCategory.filter(categoryEntity -> Objects.equals(root.getCatId(), categoryEntity.getParentCid()));

        Stream<CategoryEntity> peek = children.peek(categoryEntity -> categoryEntity.setChildren(getChildren(categoryEntity, all)));

        Stream<CategoryEntity> sortedChildren = peek.sorted(Comparator.comparingInt(menu -> (menu.getSort() == null ? 0 : menu.getSort())));

        return sortedChildren.collect(Collectors.toList());
    }
}